package cn.sciento.farm.devicemanager.gateway.uplink.service.lorawan;

import cn.sciento.farm.devicemanager.common.constant.DeviceConstant;
import cn.sciento.farm.devicemanager.common.constant.MqttConstant;
import cn.sciento.farm.devicemanager.common.exception.NullDeviceTypeException;
import cn.sciento.farm.devicemanager.common.util.NumberUtil;
import cn.sciento.farm.devicemanager.dao.entity.DevCollectionType;
import cn.sciento.farm.devicemanager.gateway.model.uplink.*;
import cn.sciento.farm.devicemanager.gateway.model.lorawan.DeviceAck;
import cn.sciento.farm.devicemanager.gateway.model.lorawan.DeviceError;
import cn.sciento.farm.devicemanager.gateway.model.lorawan.DeviceJoin;
import cn.sciento.farm.devicemanager.gateway.model.lorawan.DeviceRx;
import cn.sciento.farm.devicemanager.gateway.uplink.service.base.AbstractStringAdapter;
import cn.sciento.farm.devicemanager.gateway.uplink.service.sensor.MessageAllDisposeService;
import cn.sciento.farm.devicemanager.service.CollectionTypeService;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.beans.Expression;
import java.util.*;

/**
 * @author wumu
 * @version V1.0
 * @date 9/20/18
 * @time 5:24 PM
 */
@Service(value = MqttConstant.PROTOCOL_PREFIX + MqttConstant.PROTOCOL_LORAWAN)
public class LoraWanDataAdapter extends AbstractStringAdapter {

    Logger logger = LoggerFactory.getLogger(getClass());


    @Autowired
    private MessageAllDisposeService messageAllDisposeService;



    @Autowired
    private LorawanHeartListener lorawanHeartListener;

    @Autowired
    private CollectionTypeService collectionTypeService;

    @Override
    public void analyseStringData(String[] subTopic, String message) {
        logger.info("适配器  topic  {}  msg   {}", Arrays.toString(subTopic),message);
        if (subTopic.length == 6) {
            // 处理app server
            String messageType = subTopic[5];
            switch (messageType) {
                case "rx":
                    DeviceRx deviceRx = JSON.parseObject(message, DeviceRx.class);
                    System.out.println(deviceRx);
                    handleData(deviceRx);
                    break;
                case "status":
//                    LorawanDeviceStatus lorawanDeviceStatus = JSON.parseObject(msg, LorawanDeviceStatus.class);
//                    logger.info("lorawan状态："+ lorawanDeviceStatus);
//                    DevDevice deviceConcentrator = new DevDevice();
//                    deviceConcentrator.setId(lorawanDeviceStatus.getDevEUI());
//                    messageAllDisposeService.configureSys(deviceConcentrator);
                    break;
                case "join":
                    DeviceJoin deviceJoin = JSON.parseObject(message, DeviceJoin.class);
                    handleJoinData(deviceJoin);
                    break;
                case "ack":
                    DeviceAck deviceAck = JSON.parseObject(message, DeviceAck.class);
                    break;
                case "error":
                    DeviceError deviceError = JSON.parseObject(message, DeviceError.class);
                    break;
                default:
                    return;
            }
        } else if (subTopic.length == 4) {
            // 临时处理network server ，临时的解决方案，处理节点的上下线问题
            String messageType = subTopic[3];
            switch (messageType) {
                case "temp":
                    LorawanUplinkPacket lorawanUplinkPacket = JSON.parseObject(message,LorawanUplinkPacket.class);
                    if(lorawanUplinkPacket != null){
                        String devEUI = Hex.encodeHexString(Base64.getDecoder().decode(lorawanUplinkPacket.getDevEui()));
//                        logger.info("lorawan上发包的devEUI： "+ devEUI);
                        lorawanHeartListener.saveHeart(devEUI);
                    }

                    break;
                default:
                    return;
            }
        } else {
            return;
        }
    }

    private void handleJoinData(DeviceJoin deviceJoin) {
        String devDUI = deviceJoin.getDevEUI();
        logger.info("设备入网消息：" + deviceJoin);
        DeviceStatus deviceStatus = DeviceStatus.builder()
                .eui(devDUI)
                .node(null)
                .extraNode(null)
                .status(MqttConstant.NODE_JOIN_CODE)
                .build();
        messageAllDisposeService.changeOnline(deviceStatus);
    }


    private List<LoraWanDataNode> analyzeData(byte[] bytes) {
        if (bytes.length < 3) {
            logger.warn("上传的数据长度过短：" + Arrays.toString(bytes));
            return Collections.EMPTY_LIST;
        }
        List<LoraWanDataNode> dataNodeList = new ArrayList<>();
        int[] payload = new int[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            payload[i] = bytes[i] & 0x0FF;
        }
        logger.info("转换为int的数组：" + Arrays.toString(payload));
        /*
         skip
         0 数据开始
         采集
         1-10 后面是数据
         20 后面是类型
          */
        int skip = 0;
        int lastData = 0;
        int channelNo = 0;
        int length = 0;
        int type = 0;
        for (int i = 0; i < payload.length; i++) {
            if (skip == 0) {
                lastData = payload[i];
                channelNo = lastData / 16;
                length = lastData % 16;
                skip = 20;
            } else if (skip == 20) {
                type = payload[i];
                skip = length;
            } else if (skip > 0 && skip < 20) {
                if (skip == 1) {
                    int[] childBytes = new int[length];
                    System.arraycopy(payload, i - length + 1, childBytes, 0, length);
                    LoraWanDataNode loraWanDataNode = new LoraWanDataNode();
                    loraWanDataNode.setBytes(childBytes);
                    loraWanDataNode.setChannelNo(channelNo);
                    loraWanDataNode.setType(type);
                    loraWanDataNode.setLength(length);
                    dataNodeList.add(loraWanDataNode);
                    --skip;
                } else {
                    --skip;
                    continue;
                }
            }
            if (skip > 20) {
                logger.warn("loranwan异常的长度");
                return Collections.EMPTY_LIST;
            }
        }
        if (skip == 0) {
            // 协议正常处理完毕
            for (LoraWanDataNode loraWanDataNode : dataNodeList) {
                loraWanDataNode.convertData();
            }
            logger.info("解析后的数据：" + dataNodeList);
            return dataNodeList;
        } else {
            // 协议没有正常处理完毕
            logger.warn("lorawan发送的数据不符合要求");
            return Collections.EMPTY_LIST;
        }

    }


    private float computeRealValue(DevCollectionType devCollectionType, int value) {
        double realValue = value*1.0/ devCollectionType.getProportion();
        // 执行表达式
        return NumberUtil.double2float(realValue, 2);
    }


    private void handleData(DeviceRx deviceRx) {
        String data = deviceRx.getData();
        byte[] dataBytes = Base64.getDecoder().decode(data);
        List<LoraWanDataNode> dataNodeList = analyzeData(dataBytes);
        for (LoraWanDataNode loraWanDataNode : dataNodeList) {
            int channelNo = loraWanDataNode.getChannelNo();
            int type = loraWanDataNode.getType();
            if (type > 100) {
                CollectionData deviceData = new CollectionData();
                // todo lorawan节点的网关的数据没有进行获取
                deviceData.setEui(deviceRx.getDevEUI());
                deviceData.setNode(channelNo + "");

                deviceData.setSerial(loraWanDataNode.getType());

                int originData = loraWanDataNode.getData();
                DevCollectionType collectionType = collectionTypeService.getBySerial(loraWanDataNode.getType());
                if (collectionType == null) {
                    continue;
                }
                deviceData.setData(computeRealValue(collectionType, originData));
                deviceData.setType(collectionType.getId());
                deviceData.setCircuit(collectionType.getId());
                deviceData.setProtocol(DeviceConstant.LORAWAN);
                deviceData.setName(collectionType.getName());
                messageAllDisposeService.changeDeviceData(deviceData);
            } else if (type == 0) {
                // 控制
                ControlData switchStatus = new ControlData();
                switchStatus.setEui(deviceRx.getDevEUI());
                switchStatus.setNode(null);
                switchStatus.setCircuit(channelNo + "");
                switchStatus.setType(DeviceConstant.LORAWAN);
                switchStatus.setEn(loraWanDataNode.getData());

                messageAllDisposeService.changeSwitch(switchStatus);


            }
        }
    }
}
